#pragma once
#include "TcpServer.hpp"
#include "util.hpp"
#include <unordered_map>
#include <fstream>
#include <sstream>
#include <filesystem>

using namespace socket_module;
namespace fs = std::filesystem;

const std::string space = " ";
const std::string header_gap = ": ";
const std::string next_line = "\r\n";
const std::string home_page = "./wwwhome";
const std::string default_page = "index.html";

class requestMsg
{
public:
    requestMsg() {}
    ~requestMsg() {}

public:
    void deserialize(std::string& msg)
    {
        std::string request_line = util::readOneLine(msg, next_line);
        parseRequestLine(request_line);
        // 处理URI路径
        if (_uri == "/") {
            _uri = home_page + _uri + default_page;
        } else {
            _uri = home_page + _uri;
        }
        // 安全处理：防止路径遍历攻击
        fs::path full_path(_uri);
        _uri = full_path.lexically_normal().string();
    }

    std::string uri() const {
        return _uri;
    }

private:
    void parseRequestLine(const std::string& requestLine)
    {
        std::stringstream ss(requestLine);
        ss >> _method >> _uri >> _version;
    }

private:
    std::string _method;
    std::string _uri;
    std::string _version;
    std::unordered_map<std::string, std::string> _request_header;
    std::string _text;
};

class responseMsg
{
public:
    responseMsg() : _code(200), _des_code("OK"), _version("HTTP/1.1") {}

public:
    std::string serialize()
    {
        std::stringstream ret;
        // 状态行
        ret << _version << space << _code << space << _des_code << next_line;
        
        // 响应头
        for (auto& header : _rsp_header) {
            ret << header.first << header_gap << header.second << next_line;
        }
        
        // 空行
        ret << next_line;
        
        // 正文
        if (!_text.empty()) {
            ret << _text;
        }
        return ret.str();
    }

    void make_response(const std::string& target_file)
    {
        if (!fs::exists(target_file)) {
            set_error_response(404, "Not Found");
            return;
        }

        std::ifstream file(target_file, std::ios::binary);
        if (!file.is_open()) {
            set_error_response(500, "Internal Server Error");
            return;
        }

        std::stringstream buffer;
        buffer << file.rdbuf();
        _text = buffer.str();

        // 设置正确的Content-Length
        _rsp_header["Content-Length"] = std::to_string(_text.size());
        
        // 根据文件扩展名设置Content-Type
        std::string extension = fs::path(target_file).extension().string();
        if (extension == ".html") {
            _rsp_header["Content-Type"] = "text/html";
        } else if (extension == ".css") {
            _rsp_header["Content-Type"] = "text/css";
        } else if (extension == ".js") {
            _rsp_header["Content-Type"] = "application/javascript";
        } else {
            _rsp_header["Content-Type"] = "text/plain";
        }
    }

    void set_error_response(int code, const std::string& description)
    {
        _code = code;
        _des_code = description;
        _text = "<html><body><h1>" + std::to_string(code) + " " + description + "</h1></body></html>";
        _rsp_header["Content-Type"] = "text/html";
        _rsp_header["Content-Length"] = std::to_string(_text.size());
    }

private:
    std::string _version;
    int _code;
    std::string _des_code;
    std::unordered_map<std::string, std::string> _rsp_header;
    std::string _text;
};

class HttpServer
{
public:
    HttpServer(uint16_t port) : _tcp(std::make_shared<TcpServer>(port)) {}

    void Start()
    {
        _tcp->Start([this](Socket::ptr& sock, InetAddr& inet) {
            this->HandlerHttpRequest(sock, inet);
        });
    }

private:
    void HandlerHttpRequest(Socket::ptr& sock, InetAddr& inet)
    {
        requestMsg req;
        std::string msg;
        sock->Recv(&msg);
        req.deserialize(msg);
        
        responseMsg rsp;
        rsp.make_response(req.uri());
        
        std::string ret = rsp.serialize();
        sock->Send(ret);
    }

private:
    TcpServer::ptr _tcp;
};